package com.inmotion.flutter.plugin.jieli_ble_ota.jieli_ble_ota_plugin;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.jieli.jl_bt_ota.constant.ErrorCode;
import com.jieli.jl_bt_ota.constant.StateCode;
import com.jieli.jl_bt_ota.impl.BluetoothOTAManager;
import com.jieli.jl_bt_ota.interfaces.IActionCallback;
import com.jieli.jl_bt_ota.interfaces.IUpgradeCallback;
import com.jieli.jl_bt_ota.model.base.BaseError;
import com.jieli.jl_bt_ota.model.response.TargetInfoResponse;

@SuppressLint("MissingPermission")
class JieliBleOtaManager {

    private final JieliBleOtaPlugin plugin;
    private final OTAManagerImpl otaManagerImpl;

    // 模拟杰里 OTA SDK 需要的 BtDevice
    private BluetoothDevice simulatedBleDevice;

    // 当前操作设备信息
    private String deviceAddress;
    private String deviceName;


    public JieliBleOtaManager(Context context, JieliBleOtaPlugin plugin, BleHandler bleHandler) {
        this.plugin = plugin;
        this.otaManagerImpl = new OTAManagerImpl(context, this, bleHandler);
        otaManagerImpl.configure(
                otaManagerImpl.getBluetoothOption()
//                        .setUseReconnect(true)
//                        .setMtu(220)
                        .setTimeoutMs(800)
                        .setUseAuthDevice(true)
        );
    }

    public void requestFirmwareState() {
        otaManagerImpl.queryMandatoryUpdate(new IActionCallback<TargetInfoResponse>() {
            @Override
            public void onSuccess(TargetInfoResponse targetInfoResponse) {
                // 需要强制更新
                Log.d("JieliOTAManager", "requestFirmwareState, onSuccess: " + targetInfoResponse.toString());
                plugin.onFirmwareStateRequested(0, true);
            }

            @Override
            public void onError(BaseError baseError) {
                Log.d("JieliOTAManager", "requestFirmwareState, onError: " + baseError.toString());
                if (baseError.getCode() == ErrorCode.ERR_NONE && baseError.getSubCode() == ErrorCode.ERR_NONE) {
                    Log.d("JieliOTAManager", "requestFirmwareState, notify flutter");
                    plugin.onFirmwareStateRequested(0, false);
                } else {
                    plugin.onFirmwareStateRequested(baseError.getSubCode(), false);
                }
            }
        });
    }

    public void notifyDeviceConnectionChanged(boolean connected, String identifier, String name) {
        this.deviceAddress = identifier;
        this.deviceName = name;
        otaManagerImpl.onBtDeviceConnection(simulateBluetoothDevice(deviceAddress), OTAManagerImpl.convertStatus(connected));
        Log.d("JieliOTAManager", "notifyDeviceConnectionChanged: connected: " + connected + ", is in ota: " + otaManagerImpl.isOTA());
        if (!connected && otaManagerImpl.isOTA()) {
            // bootloader 固件下载完成，设备端主动断开连接 (设备重启进入 bootloader)
            // 需要再次主动重连，继续下载应用程序固件
            Log.d("JieliOTAManager", "notifyDeviceConnectionChanged: request reconnect");
            plugin.onConnectRequest(deviceAddress, deviceName);
        }
    }


    public void notifyDataReceived(byte[] bytes) {
        otaManagerImpl.onReceiveDeviceData(simulateBluetoothDevice(deviceAddress), bytes);
    }

    public void startOTA(String file) {
        otaManagerImpl.configure(otaManagerImpl.getBluetoothOption().setFirmwareFilePath(file));
        otaManagerImpl.startOTA(new IUpgradeCallback() {
            @Override
            public void onStartOTA() {
                Log.d("JieliOTAManager", "onStartOTA");
            }

            @Override
            public void onNeedReconnect(String address, boolean isNewReconnectWay) {
                // 这个回调似乎不会触发
                // 在连接断开通知 (notifyDeviceConnectionChanged) 时，再触发重连
            }

            @Override
            public void onProgress(int type, float progress) {
                Log.d("JieliOTAManager", "onProgress, type: " + type + ", progress: " + progress);
                if (type == 1 && progress > 99.7f) progress = 100;
                plugin.onOTAProgressUpdated(type, progress);
            }

            @Override
            public void onStopOTA() {
                Log.d("JieliOTAManager", "onStopOTA");
                // onStop 即升级成功
                plugin.onOTAUpdateSuccess();
            }

            @Override
            public void onCancelOTA() {
                Log.d("JieliOTAManager", "onCancelOTA");
                // onCancel 在当前业务模式下不会回调
            }

            @Override
            public void onError(BaseError baseError) {
                Log.d("JieliOTAManager", "onError, " + baseError.toString());
                plugin.onOTAUpdateFailed(baseError.getCode(), baseError.getSubCode(), baseError.getOpCode());
            }
        });
    }

    private BluetoothDevice simulateBluetoothDevice(String address) {
        if (simulatedBleDevice != null && TextUtils.equals(address, simulatedBleDevice.getAddress())) {
            return simulatedBleDevice;
        }
        simulatedBleDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        return simulatedBleDevice;
    }

    public void release() {
        otaManagerImpl.release();
        simulatedBleDevice = null;
        deviceAddress = null;
        deviceName = null;
    }

    static class OTAManagerImpl extends BluetoothOTAManager {

        JieliBleOtaManager host;
        BleHandler bleHandler;

        public OTAManagerImpl(Context context, JieliBleOtaManager host, BleHandler bleHandler) {
            super(context);
            this.host = host;
            this.bleHandler = bleHandler;
        }

        @Override
        public BluetoothDevice getConnectedDevice() {
            return host.simulateBluetoothDevice(host.deviceAddress);
        }

        @Override
        public BluetoothGatt getConnectedBluetoothGatt() {
            // the gatt client is just used for managing the mtu,
            // plugin doesn't need to do this, so keep it return null
            return null;
        }

        @Override
        public void connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
            bleHandler.connect(bluetoothDevice.getAddress(), bluetoothDevice.getName());
        }

        @Override
        public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
            bleHandler.disconnect();
        }

        @Override
        public boolean sendDataToDevice(BluetoothDevice bluetoothDevice, byte[] bytes) {
            bleHandler.writeBytes(bytes);
            return true;
        }

        private static int convertStatus(boolean connected) {
            return connected ? StateCode.CONNECTION_OK : StateCode.CONNECTION_DISCONNECT;
        }
    }

    static abstract class BleHandler {
        abstract void writeBytes(byte[] bytes);

        abstract void connect(String address, String name);

        abstract void disconnect();
    }
}
